package net.chrisrichardson.ec2deployer.cluster

import net.chrisrichardson.ec2deployer.applications.MySqlServer
import org.apache.commons.logging.*
import net.chrisrichardson.ec2deployer.core.CloudManager
import net.chrisrichardson.ec2deployer.core.Application
import net.chrisrichardson.ec2deployer.core.EC2Server
import net.chrisrichardson.ec2deployer.core.ProcessExecutionException

class DatabaseTier extends AbstractTier {
    def Log logger = LogFactory.getLog(getClass())


    MySqlServer databaseServer
    List<MySqlServer> mySqlSlaves = []
    ClusterSpec spec

    protected DatabaseTier() {}

    DatabaseTier(CloudManager ec2, spec) {
        super(ec2)
        this.spec = spec
    }

    def saveState(result) {
        if (!mySqlSlaves.empty)
            result.put("mySqlSlaves", mySqlSlaves.host.instanceId)
        if (databaseServer)
            result.put("databaseServer", [databaseServer.host.instanceId])
    }

    def restoreState(serverState) {
        this.databaseServer = restoreDatabaseServer(serverState["databaseServer"])
        def slaveInstances = serverState["mySqlSlaves"]
        if (slaveInstances) {
            mySqlSlaves.clear()
            slaveInstances.each {mySqlSlaves.add new MySqlServer(ec2.findInstance(it), databaseServer, spec)}
        }
    }

    def restoreDatabaseServer(List previousInstanceId) {
        if (previousInstanceId)
            return new MySqlServer(ec2.findInstance(previousInstanceId[0]), spec)
    }

    def assignHosts(hosts) {
        databaseServer = new MySqlServer(hosts.databaseServer, spec)

        def slaveHostsIt = hosts.mySqlSlavesIterator

        spec.numberOfSlaves.times {mySqlSlaves.add(new MySqlServer(slaveHostsIt.next(), databaseServer, spec))}

        logger.debug "slaves=" + mySqlSlaves
    }

    void performStart() {

        boolean mustCreateDb = spec.mustCreateDb

        phase("Configuring database") {
            logger.info "Configuring MySQL master"

            databaseServer.configureAsMaster()

            if (mySqlSlaves)
                logger.info "Configuring MySQL slaves"

            def slaveServerId = 2
            for (slave in mySqlSlaves) {
                slave.configureAsSlave(slaveServerId)
                slaveServerId = slaveServerId + 1
            }
        }

        if (mustCreateDb)
            phase ("Executing scripts") {
                println "Creating database"
                databaseServer.dbCreateOnStartup()
            }
    }

    def dbSave(String s3Path) {
        databaseServer.dbSave(s3Path)
    }

    def dbRestore(String s3Path) {
        databaseServer.dbRestore(s3Path)
    }

    List<EC2Server> getServers() {
        [databaseServer.host] + mySqlSlaves.host
    }

    List<EC2Server> getSlaveInstances() {
        mySqlSlaves.host
    }

    EC2Server getMasterInstance() {
        databaseServer.host
    }

    def getSarMonitor() {
        databaseServer.sarMonitor
    }

    def getSarMonitorsForSlaves() {
        mySqlSlaves.sarMonitor
    }

    def dbRecreate() {
        databaseServer.dbRecreate()
    }

    def executeSqlScripts(scripts) {
        databaseServer.executeSqlScripts scripts
    }

    def initlbpool() {
        databaseServer.initlbpool(mySqlSlaves)
    }

    void grantAccessToClient(Application client) {
        databaseServer.grantAccessToClient(client)
    }

    String getDatabaseServerDnsName() {
        databaseServer.host.privateDnsName
    }

    List<String> getMySqlSlavesDnsName() {
        mySqlSlaves.host.privateDnsName
    }

    void configureMasterBackup(String bucket, String objectPrefix) {
        databaseServer.configureBackup bucket, objectPrefix, true
    }

    void configureSlaveBackup(String instanceId, String bucket, String objectPrefix) {
        def slave = mySqlSlaves.find {it.host.instanceId == instanceId}
        slave.configureBackup bucket, objectPrefix, false
    }

    String snapshotDatabase() {
        databaseServer.host.snapshotEbsVolume spec.ebsVolume, spec.schemaSpec
    }

}